﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Happy.ExtentionMethods;
using Happy.StateManager.Internal;

namespace Happy.StateManager.Configuration.Internal
{
    internal sealed class Config<TState, TOperation> :
        IConfig<TState, TOperation>,
        IInConfig<TState, TOperation>,
        IWhenConfig<TState, TOperation>,
        IIfConfig<TState, TOperation>
    {
        internal Config(Func<TState> stateGetter, Action<TState> stateSetter)
        {
            stateGetter.MustNotNull("stateGetter");
            stateSetter.MustNotNull("stateSetter");

            this.StateTable = new StateTable<TState, TOperation>(stateGetter, stateSetter);
        }

        internal StateTable<TState, TOperation> StateTable { get; set; }

        internal TState TempFromState { get; set; }

        internal TOperation TempOperation { get; set; }

        internal ICondition TempCondition { get; set; }

        internal TState TempToState { get; set; }

        IInConfig<TState, TOperation> IConfig<TState, TOperation>.In(TState fromState)
        {
            fromState.MustNotNull("fromState");

            this.TempFromState = fromState;

            return this;
        }

        StateTable<TState, TOperation> IConfig<TState, TOperation>.Done()
        {
            return this.StateTable;
        }

        IWhenConfig<TState, TOperation> IInConfig<TState, TOperation>.When(TOperation operation)
        {
            operation.MustNotNull("operation");

            this.TempOperation = operation;

            return this;
        }

        IIfConfig<TState, TOperation> IWhenConfig<TState, TOperation>.If(ICondition condition)
        {
            condition.MustNotNull("condition");

            this.TempCondition = condition;

            return this;
        }

        IIfConfig<TState, TOperation> IWhenConfig<TState, TOperation>.Aways()
        {
            this.TempCondition = TrueCondition.Singleton;

            return this;
        }

        IIfConfig<TState, TOperation> IWhenConfig<TState, TOperation>.If(Func<bool> condition)
        {
            condition.MustNotNull("condition");

            this.TempCondition = new FuncCondition(condition);

            return this;
        }

        IConfig<TState, TOperation> IIfConfig<TState, TOperation>.TransferTo(TState toState)
        {
            toState.MustNotNull("toState");

            this.TempToState = toState;

            this.StateTable.ConfigTransition(
                this.TempFromState,
                this.TempOperation,
                this.TempCondition,
                this.TempToState);

            return this;
        }


        IConfig<TState, TOperation> IIfConfig<TState, TOperation>.Ok()
        {
            this.TempToState = this.TempFromState;

            this.StateTable.ConfigTransition(
                this.TempFromState,
                this.TempOperation,
                this.TempCondition,
                this.TempToState);

            return this;
        }
    }
}
